package com.coldlz.mmp.proxy;

import com.coldlz.mmp.ssl.CASignerProvider;
import com.coldlz.mmp.ssl.CertificateContext;
import com.coldlz.mmp.ssl.RootCertificateHolder;
import com.coldlz.mmp.ssl.Util;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLException;
import java.io.File;
import java.util.Arrays;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


public class SslContextManager {

    public static final Logger log = LoggerFactory.getLogger(SslContextManager.class);
    private static final ConcurrentHashMap<String, CertificateContext> sslContextMap = new ConcurrentHashMap<>(256);
    private static volatile SslContext clientSsl;

    public static void initLoad() {
        File root = Util.getCertFile("root").getParentFile();
        File[] files = root.listFiles();
        if (files == null) {
            return;
        }
        Set<String> domains = Arrays.stream(files)
                .filter(file -> file.getName().endsWith("-cert.crt"))
                .map(file -> file.getName().replace("-cert.crt", "")).collect(Collectors.toSet());
        for (String domain : domains) {
            if (isDomain(domain)) {
                // 初始化并加载到容器里面
                ThreadPoolsUtil.cachedThreadPool.execute(() -> getServerSsl(domain));
            }
        }
    }

    public static SslContext getClientSsl() {
        if (clientSsl != null) {
            return clientSsl;
        }
        synchronized (SslContextManager.class) {
            if (clientSsl != null) {
                return clientSsl;
            }
            try {
                clientSsl = SslContextBuilder.forClient()
                        .trustManager(InsecureTrustManagerFactory.INSTANCE)
                        .build();
            } catch (SSLException e) {
                throw new RuntimeException("Failed to initialize client SSL；" + e.getMessage(), e);
            }
        }
        return clientSsl;
    }

    public static SslContext getServerSsl(String host) {
        if (!isDomain(host)) {
            throw new ProxyException("域名不符合规则");
        }
        // computeIfAbsent 原子操作 不需要进行加锁
        CertificateContext certificateContext = sslContextMap.computeIfAbsent(host, key -> {
            CASignerProvider signerProvider = RootCertificateHolder.getRootSignerProvider();
            return CertificateContext.create(host, signerProvider);
        });
        try {
            return certificateContext.getOrNewSslContext();
        } catch (SSLException e) {
            log.error("Failed to initialize SSL...");
            throw new RuntimeException(e);
        }
    }

    private static boolean isDomain(String str) {
        // 将字符串按点号（.）分割成标签数组
        String[] labels = str.split("\\.");
        // 检查每个标签是否符合域名的格式
        for (String label : labels) {
            // 检查标签的长度是否在1到63之间
            if (label.isEmpty() || label.length() > 63) {
                return false;
            }

            // 检查标签是否以连字符开头或结尾
            if (label.startsWith("-") || label.endsWith("-")) {
                return false;
            }

            // 检查标签的字符是否合法
            for (char c : label.toCharArray()) {
                if (!Character.isLetterOrDigit(c) && c != '-') {
                    return false;
                }
            }
        }
        return true;
    }
}
